/*
 * Copyright 2011 The Android Open Source Project
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.example.android.actionbarcompat;

import java.io.*;
import java.util.*;
import org.xmlpull.v1.*;
import android.app.*;
import android.content.*;
import android.content.res.*;
import android.os.*;
import android.view.*;
import android.widget.*;
import de.faap.feedme.*;

/**
 * A class that implements the action bar pattern for pre-Honeycomb devices.
 */
public class ActionBarHelperBase extends ActionBarHelper {
    private static final String MENU_RES_NAMESPACE =
            "http://schemas.android.com/apk/res/android";
    private static final String MENU_ATTR_ID = "id";
    private static final String MENU_ATTR_SHOW_AS_ACTION = "showAsAction";

    protected Set<Integer> mActionItemIds = new HashSet<Integer>();

    protected ActionBarHelperBase(Activity activity) {
        super(activity);
    }

    /** {@inheritDoc} */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
    }

    /** {@inheritDoc} */
    @Override
    public void onPostCreate(Bundle savedInstanceState) {
        mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
                                            R.layout.actionbar_compat);
        Bundle bundle = mActivity.getIntent().getExtras();

        String title;
        int icon;
        // if the bundle got information use it, else use the start-screen
        // information
        if (bundle == null) {
            title = mActivity.getString(R.string.app_name);
            icon = R.drawable.ic_home;
        } else {
            title =
                    bundle.getString(de.faap.feedme.ui.DashboardActivity.ACTIONBAR_TITLE);
            icon =
                    bundle.getInt(de.faap.feedme.ui.DashboardActivity.ACTIONBAR_ICON);
        }
        setupActionBar(title, icon);
        SimpleMenu menu = new SimpleMenu(mActivity);
        mActivity.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
        mActivity.onPrepareOptionsMenu(menu);
        for (int i = 0; i < menu.size(); i++) {
            MenuItem item = menu.getItem(i);
            if (mActionItemIds.contains(item.getItemId())) {
                addActionItemCompatFromMenuItem(item);
            }
        }
    }

    /**
     * Sets up the compatibility action bar with the given title.
     */
    private void setupActionBar(String title, int icon) {
        final ViewGroup actionBarCompat = getActionBarCompat();
        if (actionBarCompat == null) {
            return;
        }

        LinearLayout.LayoutParams springLayoutParams =
                new LinearLayout.LayoutParams(0,
                        ViewGroup.LayoutParams.FILL_PARENT);
        springLayoutParams.weight = 1;

        // Add Home button
        SimpleMenu tempMenu = new SimpleMenu(mActivity);
        SimpleMenuItem homeItem =
                new SimpleMenuItem(tempMenu, android.R.id.home, 0, title);
        homeItem.setIcon(icon);
        addActionItemCompatFromMenuItem(homeItem);

        // Add title text
        TextView titleText =
                new TextView(mActivity, null, R.attr.actionbarCompatTitleStyle);
        titleText.setLayoutParams(springLayoutParams);
        titleText.setText(title);
        actionBarCompat.addView(titleText);
    }

    /** {@inheritDoc} */
    @Override
    public void setRefreshActionItemState(boolean refreshing) {
        View refreshButton =
                mActivity.findViewById(R.id.actionbar_compat_item_refresh);
        View refreshIndicator =
                mActivity
                        .findViewById(R.id.actionbar_compat_item_refresh_progress);

        if (refreshButton != null) {
            refreshButton.setVisibility(refreshing ? View.GONE : View.VISIBLE);
        }
        if (refreshIndicator != null) {
            refreshIndicator.setVisibility(refreshing ? View.VISIBLE
                    : View.GONE);
        }
    }

    /** {@inheritDoc} */
    @Override
    public void setProgressBarState(boolean on) {
        View progressBar =
                mActivity
                        .findViewById(R.id.actionbar_compat_item_progressbar_progress);

        if (progressBar != null) {
            progressBar.setVisibility(on ? View.VISIBLE : View.GONE);
        }
    }

    /**
     * Action bar helper code to be run in
     * {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
     * 
     * NOTE: This code will mark on-screen menu items as invisible.
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Hides on-screen action items from the options menu.
        for (Integer id : mActionItemIds) {
            menu.findItem(id).setVisible(false);
        }
        return true;
    }

    /** {@inheritDoc} */
    @Override
    protected void onTitleChanged(CharSequence title, int color) {
        TextView titleView =
                (TextView) mActivity.findViewById(R.id.actionbar_compat_title);
        if (titleView != null) {
            titleView.setText(title);
        }
    }

    /**
     * Returns a {@link android.view.MenuInflater} that can read action bar
     * metadata on pre-Honeycomb devices.
     */
    @Override
    public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
        return new WrappedMenuInflater(mActivity, superMenuInflater);
    }

    /**
     * Returns the {@link android.view.ViewGroup} for the action bar on phones
     * (compatibility action bar). Can return null, and will return null on
     * Honeycomb.
     */
    private ViewGroup getActionBarCompat() {
        return (ViewGroup) mActivity.findViewById(R.id.actionbar_compat);
    }

    /**
     * Adds an action button to the compatibility action bar, using menu
     * information from a {@link android.view.MenuItem}. If the menu item ID is
     * <code>menu_refresh</code>, the menu item's state can be changed to show a
     * loading spinner using
     * {@link com.example.android.actionbarcompat.ActionBarHelperBase#setRefreshActionItemState(boolean)}
     * .
     */
    private View addActionItemCompatFromMenuItem(final MenuItem item) {
        final int itemId = item.getItemId();

        final ViewGroup actionBar = getActionBarCompat();
        if (actionBar == null) {
            return null;
        }

        // Create the button
        ImageButton actionButton =
                new ImageButton(
                        mActivity,
                        null,
                        itemId == android.R.id.home ? R.attr.actionbarCompatItemHomeStyle
                                : R.attr.actionbarCompatItemStyle);
        actionButton
                .setLayoutParams(new ViewGroup.LayoutParams(
                        (int) mActivity
                                .getResources()
                                .getDimension(itemId == android.R.id.home ? R.dimen.actionbar_compat_button_home_width
                                                      : R.dimen.actionbar_compat_button_width),
                        ViewGroup.LayoutParams.FILL_PARENT));
        if (itemId == R.id.menu_refresh) {
            actionButton.setId(R.id.actionbar_compat_item_refresh);
        } else if (itemId == R.id.menu_progressbar) {
            actionButton.setId(R.id.actionbar_compat_item_progressbar);
            // this is a dummy menu item. it is always invisible and works as a
            // placeholder for the progressbar
            actionButton.setVisibility(View.GONE);
        }
        actionButton.setImageDrawable(item.getIcon());
        actionButton.setScaleType(ImageView.ScaleType.CENTER);
        actionButton.setContentDescription(item.getTitle());

        // make the homebutton on the startactivity not clickable
        if (itemId == android.R.id.home) {
            SimpleMenuItem smi = (SimpleMenuItem) item;
            if (!smi.getTitle().equals(mActivity.getString(R.string.app_name))) {
                actionButton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        mActivity
                                .onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL,
                                                    item);
                    }
                });
            }
        } else { // make all other buttons clickable
            actionButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL,
                                                 item);
                }
            });
        }

        actionBar.addView(actionButton);

        if (item.getItemId() == R.id.menu_refresh
                || item.getItemId() == R.id.menu_progressbar) {
            // Refresh buttons should be stateful, and allow for indeterminate
            // progress indicators,
            // so add those.
            ProgressBar indicator =
                    new ProgressBar(mActivity, null,
                            R.attr.actionbarCompatProgressIndicatorStyle);

            final int buttonWidth =
                    mActivity
                            .getResources()
                            .getDimensionPixelSize(R.dimen.actionbar_compat_button_width);
            final int buttonHeight =
                    mActivity
                            .getResources()
                            .getDimensionPixelSize(R.dimen.actionbar_compat_height);
            final int progressIndicatorWidth = buttonWidth / 2;

            LinearLayout.LayoutParams indicatorLayoutParams =
                    new LinearLayout.LayoutParams(progressIndicatorWidth,
                            progressIndicatorWidth);
            indicatorLayoutParams
                    .setMargins((buttonWidth - progressIndicatorWidth) / 2,
                                (buttonHeight - progressIndicatorWidth) / 2,
                                (buttonWidth - progressIndicatorWidth) / 2, 0);
            indicator.setLayoutParams(indicatorLayoutParams);
            indicator.setVisibility(View.GONE);
            if (item.getItemId() == R.id.menu_refresh) {
                indicator.setId(R.id.actionbar_compat_item_refresh_progress);
            } else {
                indicator
                        .setId(R.id.actionbar_compat_item_progressbar_progress);
            }
            actionBar.addView(indicator);
        }

        return actionButton;
    }

    /**
     * A {@link android.view.MenuInflater} that reads action bar metadata.
     */
    private class WrappedMenuInflater extends MenuInflater {
        MenuInflater mInflater;

        public WrappedMenuInflater(Context context, MenuInflater inflater) {
            super(context);
            mInflater = inflater;
        }

        @Override
        public void inflate(int menuRes, Menu menu) {
            loadActionBarMetadata(menuRes);
            mInflater.inflate(menuRes, menu);
        }

        /**
         * Loads action bar metadata from a menu resource, storing a list of
         * menu item IDs that should be shown on-screen (i.e. those with
         * showAsAction set to always or ifRoom).
         * 
         * @param menuResId
         */
        private void loadActionBarMetadata(int menuResId) {
            XmlResourceParser parser = null;
            try {
                parser = mActivity.getResources().getXml(menuResId);

                int eventType = parser.getEventType();
                int itemId;
                int showAsAction;

                boolean eof = false;
                while (!eof) {
                    switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if (!parser.getName().equals("item")) {
                            break;
                        }

                        itemId =
                                parser.getAttributeResourceValue(MENU_RES_NAMESPACE,
                                                                 MENU_ATTR_ID,
                                                                 0);
                        if (itemId == 0) {
                            break;
                        }

                        showAsAction =
                                parser.getAttributeIntValue(MENU_RES_NAMESPACE,
                                                            MENU_ATTR_SHOW_AS_ACTION,
                                                            -1);
                        if (showAsAction == MenuItem.SHOW_AS_ACTION_ALWAYS
                                || showAsAction == MenuItem.SHOW_AS_ACTION_IF_ROOM) {
                            mActionItemIds.add(itemId);
                        }
                        break;

                    case XmlPullParser.END_DOCUMENT:
                        eof = true;
                        break;
                    }

                    eventType = parser.next();
                }
            } catch (XmlPullParserException e) {
                throw new InflateException("Error inflating menu XML", e);
            } catch (IOException e) {
                throw new InflateException("Error inflating menu XML", e);
            } finally {
                if (parser != null) {
                    parser.close();
                }
            }
        }

    }
}
